﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Ivory;
using Microsoft.Xna.Framework.Input;
using DefCore.Tools;
using DefCore.AI;
using DefCore.Core;
using System.Diagnostics;
using DefCore.Interfaces;
using FarseerPhysics.SamplesFramework;

namespace DefCore.Cameras
{
    public sealed class Camera : IViewable
    {
        public const float MaxZoomLevel = 1.5f;

        //Fields
        private LevelBase _MapAssociation;
        public Vector2 CameraTopLeft;
        public Vector2 CameraViewport;

        public float ScrollSpeed = 5.67f;
        public bool Updated { get; set; }
        public bool EnableEdgeScrolling { get; set; }

        private float _LastMouseWheelDelta = 0f;
        private float _ZoomLevel = 1;
        public float ZoomLevel 
        {
            get { return _ZoomLevel; }
            set
            {
                this._ZoomLevel = (float)Math.Round((double)MathHelper.Clamp(value, .5f, MaxZoomLevel), 1);
                Debug.WriteLine("Zoom Level {0}", ZoomLevel);
            }
        }

        public Matrix KryptonView
        {
            get
            {
                return Matrix.CreateLookAt(new Vector3(CameraViewport / 2, 0), new Vector3(CameraViewport / 2, 1), Vector3.Down);
            }
        }
        public Matrix KryptonProjection
        {
            get
            {
                return Matrix.CreateOrthographic(CameraViewport.X, CameraViewport.Y, 0, 1);
            }
        }

        public Matrix FarseerProjection
        {
            get
            {
                return Matrix.CreateOrthographicOffCenter(
                   0f,
                   ConvertUnits.ToSimUnits(CameraViewport.X),
                   ConvertUnits.ToSimUnits(CameraViewport.Y),
                   0f, 0f, 1f);
            }
        }
        public Matrix FarseerView
        {
            get
            {
                return Matrix.CreateTranslation(new Vector3(ConvertUnits.ToSimUnits(-CameraTopLeft.X), ConvertUnits.ToSimUnits(-CameraTopLeft.Y), 0));
            }
        }

        public Rectangle Viewport
        {
            get
            {
                return new Rectangle((int)CameraTopLeft.X, (int)CameraTopLeft.Y, (int)CameraViewport.X, (int)CameraViewport.Y);
            }
        }

        //Construct
        public Camera(LevelBase map)
        {
            this.ZoomLevel = 1f;
            this.Updated = true;
            this._MapAssociation = map;
            this.CameraViewport = new Vector2(Objects.GameObject.GraphicsDevice.Viewport.Width, Objects.GameObject.GraphicsDevice.Viewport.Height); 
        }

        //Methods
        private void ClampToMap()
        {
            Rectangle boundingRect = new Rectangle(0, 0,
                _MapAssociation.WorldPixelWidth,
                _MapAssociation.WorldPixelHeight);

            CameraTopLeft.X = (float)MathHelper.Clamp(CameraTopLeft.X, 0, boundingRect.Width - CameraViewport.X);
            CameraTopLeft.Y = (float)MathHelper.Clamp(CameraTopLeft.Y, 0, boundingRect.Height - CameraViewport.Y);
        }

        public void Render(SpriteBatch batch, GameTime time)
        {
            return; //nothing todo here ...
        }
        public void Solve(InputControl control, GameTime time)
        {
            #region EdgeScrolling
            if (EnableEdgeScrolling)
            {
                float minX, maxX, minY, maxY;

                minX = CameraViewport.X * 0.05f;
                maxX = CameraViewport.X * 0.95f;
                minY = CameraViewport.Y * 0.05f;
                maxY = CameraViewport.Y * 0.95f;

                Vector2 camMouseScroll = Vector2.Zero;
                if (control.MouseVect.X <= minX)
                    camMouseScroll.X = -1;
                else if (control.MouseVect.X >= maxX)
                    camMouseScroll.X = 1;

                if (control.MouseVect.Y <= minY)
                    camMouseScroll.Y = -1;
                else if (control.MouseVect.Y >= maxY)
                    camMouseScroll.Y = 1;

                if (camMouseScroll != Vector2.Zero)
                {
                    camMouseScroll.Normalize();
                    camMouseScroll *= ScrollSpeed;
                    CameraTopLeft += camMouseScroll;
                    ClampToMap();

                    return; //Dont do key movement
                }
            }
            #endregion

            #region WSAD Movement
            Updated = false;
            Vector2 camMoveDirection = Vector2.Zero;

            if (control.IsKeyDown(Keys.W) || control.IsKeyDown(Keys.Up))
                camMoveDirection.Y = -1;
            else if (control.IsKeyDown(Keys.S) || control.IsKeyDown(Keys.Down))
                camMoveDirection.Y = 1;

            if (control.IsKeyDown(Keys.A) || control.IsKeyDown(Keys.Left))
                camMoveDirection.X = -1;
            else if (control.IsKeyDown(Keys.D) || control.IsKeyDown(Keys.Right))
                camMoveDirection.X = 1;

            if (camMoveDirection != Vector2.Zero)
            {
                //camMoveDirection.Normalize();
                camMoveDirection *= ScrollSpeed;
                CameraTopLeft += camMoveDirection;
                ClampToMap();

                camMoveDirection = Vector2.Zero;
                Updated = true;
            }
            #endregion

            #region Zoom Control
            if (false)
            {
                float delta = control.GetMouseWheelDelta();

                if (delta != _LastMouseWheelDelta)
                {
                    //scroll has occured
                    float changeInDelta = _LastMouseWheelDelta - delta;

                    if (changeInDelta < 0) //zoom in
                        ZoomLevel += 0.1f;
                    else
                        ZoomLevel -= 0.1f;
                }
                _LastMouseWheelDelta = delta;
            }
            #endregion
        }

        public bool Load()
        {
            
            return true; 
        }

        public static Vector2 SizeWithZoom(Vector2 v)
        {
            return new Vector2(
                (float)Math.Round(v.X * Objects.GameCamera.ZoomLevel, 0),
                (float)Math.Round(v.Y * Objects.GameCamera.ZoomLevel, 0));
        }
        public static Rectangle SizeWithZoom(Rectangle r)
        {
            return new Rectangle(
                (int)Math.Round(r.X * Objects.GameCamera.ZoomLevel, 0),
                (int)Math.Round(r.Y * Objects.GameCamera.ZoomLevel, 0),
                (int)Math.Round(r.Width * Objects.GameCamera.ZoomLevel, 0), (int)Math.Round(r.Height * Objects.GameCamera.ZoomLevel, 0));
        }
    }
}
